#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
天翼云盘客户端实现
基于tem目录下的代码重构，支持数据库缓存存储
"""

import requests
import hashlib
import hmac
import time
import uuid
import re
import json
import os
import base64
import xml.etree.ElementTree as ET
from typing import Dict, List, Optional, Any, Union, BinaryIO
from urllib.parse import urlparse, parse_qs, urlencode, quote
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, AES
from Crypto.Util.Padding import pad
import binascii
from datetime import datetime

from ..base_client import BaseCloudClient
from .file_operations import FileOperations
from .upload_operations import UploadOperations

# 常量定义
ACCOUNT_TYPE = "02"
APP_ID = "8025431004"
CLIENT_TYPE = "10020"
VERSION = "6.2"

WEB_URL = "https://cloud.189.cn"
AUTH_URL = "https://open.e.189.cn"
API_URL = "https://api.cloud.189.cn"
UPLOAD_URL = "https://upload.cloud.189.cn"

RETURN_URL = "https://m.cloud.189.cn/zhuanti/2020/loginErrorPc/index.html"

PC = "TELEPC"
MAC = "TELEMAC"

CHANNEL_ID = "web_cloud.189.cn"

class Cloud189Client(BaseCloudClient):
    """天翼云盘客户端实现"""
    
    def __init__(self, account_id: int, username: str, password: str, enable_debug: bool = False):
        """
        初始化天翼云盘客户端
        
        Args:
            account_id: 云存储账号ID
            username: 用户名
            password: 密码
            enable_debug: 是否启用调试模式
        """
        super().__init__(account_id, username, password, enable_debug)
        
        # 配置日志
        import logging
        self.logger = logging.getLogger(f'Cloud189Client_{account_id}')
        self.logger.setLevel(logging.DEBUG)  # 强制使用DEBUG级别以便查看详细日志
        
        # 确保日志能够输出
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
        
        # 测试日志输出 - 使用print确保能看到
        print(f"[DEBUG] Cloud189Client 初始化完成，账号ID: {account_id}, 用户名: {username}")
        self.logger.info(f"Cloud189Client 初始化完成，账号ID: {account_id}, 用户名: {username}")
        
        self.session = requests.Session()
        # 设置基础请求头
        self.session.headers.update({
            'Accept': 'application/json;charset=UTF-8',
            'Referer': WEB_URL,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        })
        
        self.login_param = None
        self.family_id = None
        self.identity = None
        self.token_info = None  # 初始化token_info属性
        
        # 初始化操作模块
        self.file_ops = FileOperations(self)
        self.upload_ops = UploadOperations(self)
    
    def get_provider_name(self) -> str:
        """
        获取云盘提供商名称
        
        Returns:
            str: 提供商名称
        """
        return 'tianyi'
    
    def client_suffix(self) -> Dict[str, str]:
        """客户端后缀参数"""
        import random
        rand_num = random.randint(10000, 99999)
        rand_num2 = random.randint(1000000000, 9999999999)
        return {
            "clientType": PC,
            "version": VERSION,
            "channelId": CHANNEL_ID,
            "rand": f"{rand_num}_{rand_num2}"
        }
    
    def get_http_date_str(self) -> str:
        """获取HTTP规范时间"""
        return time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime())
    
    def timestamp(self) -> int:
        """获取时间戳(毫秒)"""
        return int(time.time() * 1000)
    
    def hmac_sha1(self, data: str, key: str) -> str:
        """HMAC-SHA1签名"""
        return hmac.new(key.encode(), data.encode(), hashlib.sha1).hexdigest()
    
    def signature_of_hmac(self, session_secret: str, session_key: str, operate: str, 
                         full_url: str, date_of_gmt: str, params: str = "") -> str:
        """HMAC签名"""
        url_path = re.search(r'://[^/]+((/[^/\s?#]+)*)', full_url).group(1)
        data = f"SessionKey={session_key}&Operate={operate}&RequestURI={url_path}&Date={date_of_gmt}"
        if params:
            data += f"&params={params}"
        
        signature = hmac.new(
            session_secret.encode(), 
            data.encode(), 
            hashlib.sha1
        ).hexdigest().upper()
        return signature
    
    def rsa_encrypt(self, public_key: str, orig_data: str) -> str:
        """RSA加密用户名密码"""
        try:
            # 处理公钥格式
            if not public_key.startswith('-----BEGIN'):
                public_key = f"-----BEGIN PUBLIC KEY-----\n{public_key}\n-----END PUBLIC KEY-----"
            
            rsa_key = RSA.import_key(public_key)
            cipher = PKCS1_v1_5.new(rsa_key)
            encrypted = cipher.encrypt(orig_data.encode())
            # 转换为大写十六进制字符串
            return binascii.hexlify(encrypted).decode().upper()
        except Exception as e:
            self.logger.error(f"RSA加密失败: {e}")
            return ""
    
    def aes_ecb_encrypt(self, data: str, key: str) -> str:
        """AES ECB加密params"""
        try:
            cipher = AES.new(key[:16].encode(), AES.MODE_ECB)
            padded_data = pad(data.encode(), AES.block_size)
            encrypted = cipher.encrypt(padded_data)
            return binascii.hexlify(encrypted).decode().upper()
        except Exception as e:
            self.logger.error(f"AES加密失败: {e}")
            return ""
    
    def signature_header(self, url: str, method: str, params: str = "", is_family: bool = False) -> Dict[str, str]:
        """生成签名头"""
        if not self.token_info:
            return {}
        
        date_of_gmt = self.get_http_date_str()
        session_key = self.token_info.get('sessionKey', '')
        session_secret = self.token_info.get('sessionSecret', '')
        
        if is_family:
            session_key = self.token_info.get('familySessionKey', '')
            session_secret = self.token_info.get('familySessionSecret', '')
        
        return {
            "Date": date_of_gmt,
            "SessionKey": session_key,
            "X-Request-ID": str(uuid.uuid4()),
            "Signature": self.signature_of_hmac(session_secret, session_key, method, url, date_of_gmt, params)
        }
    
    def encrypt_params(self, params: Dict[str, str], is_family: bool = False) -> str:
        """加密参数"""
        if not self.token_info or not params:
            return ""
        
        session_secret = self.token_info.get('sessionSecret', '')
        if is_family:
            session_secret = self.token_info.get('familySessionSecret', '')
        
        # 将参数编码为URL格式
        param_str = '&'.join([f"{k}={v}" for k, v in params.items()])
        return self.aes_ecb_encrypt(param_str, session_secret)
    
    def get_token_info(self) -> Optional[Dict[str, Any]]:
        """获取当前的令牌信息
        
        Returns:
            Dict[str, Any]: 令牌信息，包含访问令牌、刷新令牌等
        """
        if self.token_info:
            return {
                **self.token_info,
                'familyId': self.family_id,
                'identity': self.identity
            }
        return None
    
    def set_token_info(self, token_info: Dict[str, Any]) -> bool:
        """设置令牌信息
        
        Args:
            token_info: 令牌信息字典
            
        Returns:
            bool: 设置是否成功
        """
        try:
            if token_info:
                self.token_info = token_info
                self.family_id = token_info.get('familyId')
                self.identity = token_info.get('identity')
                self.logger.info(f"令牌信息已设置: {token_info.get('loginName', 'Unknown')}")
                return True
            else:
                self.token_info = None
                self.family_id = None
                self.identity = None
                self.logger.info("令牌信息已清除")
                return True
        except Exception as e:
            self.logger.error(f"设置令牌信息失败: {e}")
            return False
    
    def is_login(self) -> bool:
        """
        检查是否已登录
        
        Returns:
            bool: 是否已登录
        """
        if self.token_info is None:
            return False
        
        # 通过调用getUserInfo接口验证登录状态
        try:
            url = f"{API_URL}/getUserInfo.action"
            params = self.client_suffix()
            headers = self.signature_header(url, "GET")
            response = self.session.get(url, params=params, headers=headers)
            
            if response.status_code == 200:
                result = response.json()
                return result.get('res_code') == 0 or result.get('resCode') == 0
        except Exception as e:
            self.logger.error(f"检查登录状态失败: {e}")
        return False
    
    def logout(self) -> bool:
        """
        登出并清理缓存
        
        Returns:
            bool: 登出是否成功
        """
        try:
            # 清理令牌信息
            self.set_token_info(None)
            
            # 清理内存中的令牌信息
            self.token_info = None
            self.login_param = None
            self.family_id = None
            self.identity = None
            
            # 清理session cookies
            self.session.cookies.clear()
            
            self.logger.info("登出成功")
            return True
        except Exception as e:
            self.logger.error(f"登出失败: {e}")
            return False
    
    def check_login_status(self) -> bool:
        """
        检查登录状态（兼容性方法）
        
        Returns:
            bool: 是否已登录
        """
        return self.is_login()
    
    def check_login_status_only(self) -> bool:
        """
        仅检测登录状态，不进行自动登录
        
        Returns:
            bool: 是否已登录（基于现有token）
        """
        if self.token_info is None:
            return False
        
        # 通过调用getUserInfo接口验证登录状态，但不进行自动登录
        try:
            url = f"{API_URL}/getUserInfo.action"
            params = self.client_suffix()
            headers = self.signature_header(url, "GET")
            response = self.session.get(url, params=params, headers=headers)
            
            if response.status_code == 200:
                result = response.json()
                return result.get('res_code') == 0 or result.get('resCode') == 0
        except Exception as e:
            self.logger.error(f"检查登录状态失败: {e}")
        return False
    
    def login_with_credentials(self, username: str = None, password: str = None) -> bool:
        """
        使用用户名密码进行初始登录
        
        Args:
            username: 用户名（可选，默认使用初始化时的用户名）
            password: 密码（可选，默认使用初始化时的密码）
        
        Returns:
            bool: 登录是否成功
        """
        # 使用提供的用户名密码或默认值
        login_username = username or self.username
        login_password = password or self.password
        
        print(f"[DEBUG] 开始使用用户名密码登录天翼云盘，用户名: {login_username}")
        
        # 检查密码是否为None
        if login_password is None:
            print(f"[DEBUG] 密码为None，无法进行登录")
            self.logger.error("密码为None，无法进行登录")
            return False
        
        # 生成身份标识
        new_identity = hashlib.md5((login_username + login_password).encode()).hexdigest()
        
        # 获取登录参数
        print(f"[DEBUG] 开始获取登录参数...")
        if not self.get_login_param():
            print(f"[DEBUG] 获取登录参数失败")
            return False
        
        print(f"[DEBUG] 登录参数获取成功，开始RSA加密...")
        # RSA加密用户名和密码
        rsa_username = self.rsa_encrypt(self.login_param['jRsaKey'], login_username)
        rsa_password = self.rsa_encrypt(self.login_param['jRsaKey'], login_password)
        
        if not rsa_username or not rsa_password:
            print(f"[DEBUG] 加密用户名密码失败")
            self.logger.error("加密用户名密码失败")
            return False
        
        # 添加前缀
        pre = self.login_param['pre']
        rsa_username = pre + rsa_username
        rsa_password = pre + rsa_password
        
        # 登录请求
        login_url = f"{AUTH_URL}/api/logbox/oauth2/loginSubmit.do"
        login_data = {
            'appKey': APP_ID,
            'accountType': ACCOUNT_TYPE,
            'userName': rsa_username,
            'password': rsa_password,
            'validateCode': '',
            'captchaToken': self.login_param.get('captchaToken', ''),
            'returnUrl': RETURN_URL,
            'dynamicCheck': 'FALSE',
            'clientType': CLIENT_TYPE,
            'cb_SaveName': '1',
            'isOauth2': 'false',
            'state': '',
            'paramId': self.login_param['paramId']
        }
        
        headers = {
            'REQID': self.login_param['reqId'],
            'lt': self.login_param['lt']
        }
        
        try:
            print(f"[DEBUG] 发送登录请求到: {login_url}")
            response = self.session.post(login_url, data=login_data, headers=headers)
            print(f"[DEBUG] 登录请求响应状态码: {response.status_code}")
            if response.status_code == 200:
                result = response.json()
                print(f"[DEBUG] 登录响应结果: {result}")
                if result.get('result') == 0:
                    # 登录成功，获取重定向URL
                    to_url = result.get('toUrl')
                    print(f"[DEBUG] 登录成功，重定向URL: {to_url}")
                    if to_url:
                        # 获取Session
                        session_url = f"{API_URL}/getSessionForPC.action"
                        session_params = self.client_suffix()
                        session_params['redirectURL'] = to_url
                        
                        session_response = self.session.post(session_url, params=session_params)
                        if session_response.status_code == 200:
                            session_result = session_response.json()
                            # 检查不同的响应字段
                            res_code = session_result.get('resCode') or session_result.get('res_code')
                            if res_code == 0:
                                self.token_info = session_result
                                self.identity = new_identity
                                self.set_token_info(self.token_info)
                                self.logger.info(f"登录成功: {self.token_info.get('loginName', login_username)}")
                                return True
                            else:
                                res_message = session_result.get('resMessage') or session_result.get('res_message')
                                self.logger.error(f"获取session失败: {res_message}")
                else:
                    self.logger.error(f"登录失败: {result.get('msg', '未知错误')}")
        except Exception as e:
            self.logger.error(f"登录请求失败: {e}")
        
        return False
    
    def get_encrypt_conf(self) -> Optional[Dict[str, Any]]:
        """获取加密配置"""
        url = f"{AUTH_URL}/api/logbox/config/encryptConf.do"
        data = {'appId': APP_ID}
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
        
        try:
            response = self.session.post(url, data=data, headers=headers)
            if response.status_code == 200:
                return response.json()
        except Exception as e:
            self.logger.error(f"获取加密配置失败: {e}")
        return None
    
    def get_login_param(self) -> bool:
        """获取登录参数"""
        # 清除cookie
        self.session.cookies.clear()
        
        # 获取登录页面参数
        login_url = f"{WEB_URL}/api/portal/unifyLoginForPC.action"
        params = {
            'appId': APP_ID,
            'clientType': CLIENT_TYPE,
            'returnURL': RETURN_URL,
            'timeStamp': str(self.timestamp())
        }
        
        try:
            response = self.session.get(login_url, params=params)
            if response.status_code == 200:
                content = response.text
                # 使用正则表达式提取参数
                captcha_token_match = re.search(r"'captchaToken' value='(.+?)'|", content)
                lt_match = re.search(r'lt = "(.+?)"', content)
                param_id_match = re.search(r'paramId = "(.+?)"', content)
                req_id_match = re.search(r'reqId = "(.+?)"', content)
                
                if not all([captcha_token_match, lt_match, param_id_match, req_id_match]):
                    self.logger.error("解析登录页面参数失败")
                    return False
                
                # 获取加密配置
                encrypt_conf = self.get_encrypt_conf()
                if not encrypt_conf or encrypt_conf.get('result') != 0:
                    self.logger.error("获取加密配置失败")
                    return False
                
                pub_key = encrypt_conf['data']['pubKey']
                pre = encrypt_conf['data']['pre']
                
                # 构建完整的RSA公钥
                rsa_key = f"-----BEGIN PUBLIC KEY-----\n{pub_key}\n-----END PUBLIC KEY-----"
                
                self.login_param = {
                    'captchaToken': captcha_token_match.group(1),
                    'lt': lt_match.group(1),
                    'paramId': param_id_match.group(1),
                    'reqId': req_id_match.group(1),
                    'jRsaKey': rsa_key,
                    'pre': pre
                }
                return True
        except Exception as e:
            self.logger.error(f"获取登录参数失败: {e}")
        return False
    
    def login(self) -> bool:
        """登录天翼云盘"""
        print(f"[DEBUG] 开始登录天翼云盘，用户名: {self.username}")
        
        # 检查密码是否为None
        if self.password is None:
            print(f"[DEBUG] 密码为None，无法进行登录")
            self.logger.error("密码为None，无法进行登录")
            return False
        
        # 生成身份标识
        new_identity = hashlib.md5((self.username + self.password).encode()).hexdigest()
        
        # 如果已登录且身份相同，直接返回
        if self.check_login_status() and self.identity == new_identity:
            print(f"[DEBUG] 已登录，无需重复登录")
            self.logger.info("已登录，无需重复登录")
            return True
        
        # 获取登录参数
        print(f"[DEBUG] 开始获取登录参数...")
        if not self.get_login_param():
            print(f"[DEBUG] 获取登录参数失败")
            return False
        
        print(f"[DEBUG] 登录参数获取成功，开始RSA加密...")
        # RSA加密用户名和密码
        rsa_username = self.rsa_encrypt(self.login_param['jRsaKey'], self.username)
        rsa_password = self.rsa_encrypt(self.login_param['jRsaKey'], self.password)
        
        if not rsa_username or not rsa_password:
            print(f"[DEBUG] 加密用户名密码失败")
            self.logger.error("加密用户名密码失败")
            return False
        
        # 添加前缀
        pre = self.login_param['pre']
        rsa_username = pre + rsa_username
        rsa_password = pre + rsa_password
        
        # 登录请求
        login_url = f"{AUTH_URL}/api/logbox/oauth2/loginSubmit.do"
        login_data = {
            'appKey': APP_ID,
            'accountType': ACCOUNT_TYPE,
            'userName': rsa_username,
            'password': rsa_password,
            'validateCode': '',
            'captchaToken': self.login_param.get('captchaToken', ''),
            'returnUrl': RETURN_URL,
            'dynamicCheck': 'FALSE',
            'clientType': CLIENT_TYPE,
            'cb_SaveName': '1',
            'isOauth2': 'false',
            'state': '',
            'paramId': self.login_param['paramId']
        }
        
        headers = {
            'REQID': self.login_param['reqId'],
            'lt': self.login_param['lt']
        }
        
        try:
            print(f"[DEBUG] 发送登录请求到: {login_url}")
            response = self.session.post(login_url, data=login_data, headers=headers)
            print(f"[DEBUG] 登录请求响应状态码: {response.status_code}")
            if response.status_code == 200:
                result = response.json()
                print(f"[DEBUG] 登录响应结果: {result}")
                if result.get('result') == 0:
                    # 登录成功，获取重定向URL
                    to_url = result.get('toUrl')
                    print(f"[DEBUG] 登录成功，重定向URL: {to_url}")
                    if to_url:
                        # 获取Session
                        session_url = f"{API_URL}/getSessionForPC.action"
                        session_params = self.client_suffix()
                        session_params['redirectURL'] = to_url
                        
                        session_response = self.session.post(session_url, params=session_params)
                        if session_response.status_code == 200:
                            session_result = session_response.json()
                            # 检查不同的响应字段
                            res_code = session_result.get('resCode') or session_result.get('res_code')
                            if res_code == 0:
                                self.token_info = session_result
                                self.identity = new_identity
                                self.set_token_info(self.token_info)
                                self.logger.info(f"登录成功: {self.token_info.get('loginName', self.username)}")
                                return True
                            else:
                                res_message = session_result.get('resMessage') or session_result.get('res_message')
                                self.logger.error(f"获取session失败: {res_message}")
                else:
                    self.logger.error(f"登录失败: {result.get('msg', '未知错误')}")
        except Exception as e:
            self.logger.error(f"登录请求失败: {e}")
        
        return False
    
    def refresh_token(self) -> bool:
        """刷新登录令牌"""
        if not self.token_info or 'accessToken' not in self.token_info:
            self.logger.error("没有有效的accessToken，尝试重新登录")
            return self.login()
            
        url = f"{API_URL}/getSessionForPC.action"
        params = self.client_suffix()
        params.update({
            'appId': APP_ID,
            'accessToken': self.token_info['accessToken']
        })
        
        headers = {
            'X-Request-ID': str(uuid.uuid4())
        }
        
        try:
            response = self.session.get(url, params=params, headers=headers)
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0:
                    # 更新token信息
                    self.token_info.update(result)
                    self.set_token_info(self.token_info)
                    self.logger.info("Token刷新成功")
                    return True
                else:
                    self.logger.error(f"刷新token失败: {result.get('res_message')}")
                    # 如果token无效，清理缓存并尝试重新登录
                    if result.get('resCode') == 'UserInvalidOpenToken':
                        self.logger.info("Token已失效，清理缓存并重新登录")
                        self.set_token_info(None)
                    return self.login()
            else:
                self.logger.error(f"Token刷新请求失败: {response.status_code}")
                return self.login()
        except Exception as e:
            self.logger.error(f"刷新token失败: {e}")
            return self.login()
    
    def get_user_info(self) -> Optional[Dict[str, Any]]:
        """获取用户信息"""
        if not self.check_login_status():
            if not self.login():
                return None
        
        url = f"{API_URL}/getUserInfo.action"
        params = self.client_suffix()
        headers = self.signature_header(url, "GET")
        
        try:
            response = self.session.get(url, params=params, headers=headers)
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    return result
                else:
                    self.logger.error(f"获取用户信息失败: {result.get('res_message', result.get('resMessage'))}")
        except Exception as e:
            self.logger.error(f"获取用户信息请求失败: {e}")
        return None
    
    def get_files(self, folder_id: str = None, is_family: bool = False) -> Optional[Dict[str, Any]]:
        """获取文件列表"""
        if not self.check_login_status():
            if not self.login():
                return None
        
        if folder_id is None:
            folder_id = "-11"  # 根目录
        
        url = f"{API_URL}/listFiles.action"
        params = {
            'folderId': folder_id,
            'mediaType': 0,
            'iconOption': 5,
            'orderBy': 'lastOpTime',
            'descending': 'true',
            'pageNum': 1,
            'pageSize': 60
        }
        params.update(self.client_suffix())
        
        headers = self.signature_header(url, "GET", is_family=is_family)
        
        try:
            response = self.session.get(url, params=params, headers=headers)
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    return result
                else:
                    self.logger.error(f"获取文件列表失败: {result.get('res_message', result.get('resMessage'))}")
        except Exception as e:
            self.logger.error(f"获取文件列表请求失败: {e}")
        return None
    
    def upload_file(self, file_data: Union[str, bytes, BinaryIO], filename: str, 
                   parent_id: str = None, overwrite: bool = True) -> Optional[Dict[str, Any]]:
        """上传文件
        
        Args:
            file_data: 文件数据（文件路径、字节数据或文件对象）
            filename: 文件名
            parent_id: 父文件夹ID，None表示根目录
            overwrite: 是否覆盖同名文件
        
        Returns:
            Dict[str, Any]: 上传成功返回文件信息，失败返回None
        """
        return self.upload_ops.upload_file(file_data, filename, parent_id, overwrite)
    
    def download_file(self, file_id: str, save_path: str = None) -> Union[bool, bytes, None]:
        """下载文件
        
        Args:
            file_id: 文件ID
            save_path: 保存路径，None表示返回文件内容
        
        Returns:
            Union[bool, bytes, None]: 保存到文件返回bool，返回内容返回bytes，失败返回None
        """
        return self.file_ops.download_file(file_id, save_path)
    
    def delete_file(self, file_id: str) -> bool:
        """删除文件
        
        Args:
            file_id: 文件ID
        
        Returns:
            bool: 删除是否成功
        """
        return self.file_ops.delete_file(file_id)
    
    def create_folder(self, name: str, parent_id: str = None) -> Optional[Dict[str, Any]]:
        """创建文件夹
        
        Args:
            name: 文件夹名称
            parent_id: 父文件夹ID，None表示根目录
        
        Returns:
            Dict[str, Any]: 创建成功返回文件夹信息，失败返回None
        """
        return self.file_ops.create_folder(name, parent_id)
    
    def get_files(self, folder_id: str = None, page: int = 1, 
                 page_size: int = 100) -> Optional[List[Dict[str, Any]]]:
        """获取文件列表
        
        Args:
            folder_id: 文件夹ID，None表示根目录
            page: 页码
            page_size: 每页数量
        
        Returns:
            List[Dict[str, Any]]: 文件列表
        """
        return self.file_ops.get_files(folder_id, page, page_size)
    
    def get_file_info(self, file_id: str) -> Optional[Dict[str, Any]]:
        """获取文件信息
        
        Args:
            file_id: 文件ID
        
        Returns:
            Dict[str, Any]: 文件信息
        """
        return self.file_ops.get_file_info(file_id)
    
    def delete_folder(self, folder_id: str) -> bool:
        """删除文件夹
        
        Args:
            folder_id: 文件夹ID
        
        Returns:
            bool: 删除是否成功
        """
        return self.file_ops.delete_folder(folder_id)
    
    def rename_folder(self, folder_id: str, new_name: str) -> bool:
        """重命名文件夹
        
        Args:
            folder_id: 文件夹ID
            new_name: 新名称
        
        Returns:
            bool: 重命名是否成功
        """
        return self.file_ops.rename_folder(folder_id, new_name)
    
    def rename_file(self, file_id: str, new_name: str) -> bool:
        """重命名文件
        
        Args:
            file_id: 文件ID
            new_name: 新名称
        
        Returns:
            bool: 重命名是否成功
        """
        return self.file_ops.rename_file(file_id, new_name)
    
    def move_file(self, file_id: str, target_folder_id: str) -> bool:
        """移动文件
        
        Args:
            file_id: 文件ID
            target_folder_id: 目标文件夹ID
        
        Returns:
            bool: 移动是否成功
        """
        return self.file_ops.move_file(file_id, target_folder_id)
    
    def copy_file(self, file_id: str, target_folder_id: str, new_name: str = None) -> Optional[Dict[str, Any]]:
        """复制文件
        
        Args:
            file_id: 文件ID
            target_folder_id: 目标文件夹ID
            new_name: 新文件名，None表示保持原名
        
        Returns:
            Dict[str, Any]: 复制成功返回新文件信息，失败返回None
        """
        return self.file_ops.copy_file(file_id, target_folder_id, new_name)
    
    def check_fast_upload(self, filename: str, file_size: int, file_md5: str, 
                         parent_id: str = None) -> bool:
        """检查文件是否支持秒传
        
        Args:
            filename: 文件名
            file_size: 文件大小（字节）
            file_md5: 文件MD5值
            parent_id: 父文件夹ID
        
        Returns:
            bool: 是否支持秒传
        """
        return self.upload_ops.check_fast_upload(filename, file_size, file_md5, parent_id)
    
    def fast_upload(self, filename: str, file_size: int, file_md5: str, 
                   parent_id: str = None) -> Optional[Dict[str, Any]]:
        """执行秒传
        
        Args:
            filename: 文件名
            file_size: 文件大小（字节）
            file_md5: 文件MD5值
            parent_id: 父文件夹ID
        
        Returns:
            Dict[str, Any]: 秒传成功返回文件信息，失败返回None
        """
        return self.upload_ops.fast_upload(filename, file_size, file_md5, parent_id)